import { Directive } from 'vue';
/**
 *
 * @param component 需要注册的组件
 * @param alias 组件别名
 * @returns any
 */
export const withInstall = <T>(component: T, alias?: string) => {
	const comp = component as any;
	comp.install = (app: any) => {
		app.component(comp.name || comp.displayName, component);
		if (alias) {
			app.config.globalProperties[alias] = component;
		}
	};
	return component as T & Plugin;
};

/**
 * @param str 需要转下划线的驼峰字符串
 * @returns 字符串下划线
 */
export const humpToUnderline = (str: string): string => {
	return str.replace(/([A-Z])/g, '-$1').toLowerCase();
};

/**
 * @param str 需要转驼峰的下划线字符串
 * @returns 字符串驼峰
 */
export const underlineToHump = (str: string): string => {
	if (!str) return '';
	return str.replace(/\-(\w)/g, (_, letter: string) => {
		return letter.toUpperCase();
	});
};

export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
	dom.style.setProperty(prop, val);
};

/**
 * 查找数组对象的某个下标
 * @param {Array} ary 查找的数组
 * @param {Functon} fn 判断的方法
 */
// eslint-disable-next-line
export const findIndex = <T = Recordable>(ary: Array<T>, fn: Fn): number => {
	if (ary.findIndex) {
		return ary.findIndex(fn);
	}
	let index = -1;
	ary.some((item: T, i: number, ary: Array<T>) => {
		const ret: T = fn(item, i, ary);
		if (ret) {
			index = i;
			return ret;
		}
	});
	return index;
};

export const trim = (str: string) => {
	return str.replace(/(^\s*)|(\s*$)/g, '');
};

/**
 * @param {Date | number | string} time 需要转换的时间
 * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
 */
export const formatTime = (time: Date | number | string, fmt: string) => {
	if (!time) return '';
	else {
		const date = new Date(time);
		const o = {
			'M+': date.getMonth() + 1,
			'd+': date.getDate(),
			'H+': date.getHours(),
			'm+': date.getMinutes(),
			's+': date.getSeconds(),
			'q+': Math.floor((date.getMonth() + 3) / 3),
			S: date.getMilliseconds()
		};
		if (/(y+)/.test(fmt)) {
			fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
		}
		for (const k in o) {
			if (new RegExp('(' + k + ')').test(fmt)) {
				fmt = fmt.replace(
					RegExp.$1,
					RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
				);
			}
		}
		return fmt;
	}
};

/**
 * 生成随机字符串
 */
export const toAnyString = () => {
	const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
		const r: number = (Math.random() * 16) | 0;
		const v: number = c === 'x' ? r : (r & 0x3) | 0x8;
		return v.toString();
	});
	return str;
};

export const generateUUID = () => {
	if (typeof crypto === 'object') {
		if (typeof crypto.randomUUID === 'function') {
			return crypto.randomUUID();
		}
		if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') {
			const callback = (c: any) => {
				const num = Number(c);
				return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(
					16
				);
			};
			return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback);
		}
	}
	let timestamp = new Date().getTime();
	let performanceNow =
		(typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0;
	return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
		let random = Math.random() * 16;
		if (timestamp > 0) {
			random = (timestamp + random) % 16 | 0;
			timestamp = Math.floor(timestamp / 16);
		} else {
			random = (performanceNow + random) % 16 | 0;
			performanceNow = Math.floor(performanceNow / 16);
		}
		return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16);
	});
};

/**
 * element plus 的文件大小 Formatter 实现
 *
 * @param row 行数据
 * @param column 字段
 * @param cellValue 字段值
 */
// @ts-ignore
export const fileSizeFormatter = (row, column, cellValue) => {
	const fileSize = cellValue;
	const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	const srcSize = parseFloat(fileSize);
	const index = Math.floor(Math.log(srcSize) / Math.log(1024));
	const size = srcSize / Math.pow(1024, index);
	const sizeStr = size.toFixed(2); //保留的小数位数
	return sizeStr + ' ' + unitArr[index];
};

/**
 * 将值复制到目标对象，且以目标对象属性为准，例：target: {a:1} source:{a:2,b:3} 结果为：{a:2}
 * @param target 目标对象
 * @param source 源对象
 */
export const copyValueToTarget = (target, source) => {
	const newObj = Object.assign({}, target, source);
	// 删除多余属性
	Object.keys(newObj).forEach((key) => {
		// 如果不是target中的属性则删除
		if (Object.keys(target).indexOf(key) === -1) {
			delete newObj[key];
		}
	});
	// 更新目标对象值
	Object.assign(target, newObj);
};

// TODO @puhui999：返回要带上 .00 哈.例如说 1.00
/**
 * 将一个整数转换为分数保留两位小数
 * @param num
 */
export const formatToFraction = (num: number | string | undefined): number => {
	if (typeof num === 'undefined') return 0;
	const parsedNumber = typeof num === 'string' ? parseFloat(num) : num;
	return parseFloat((parsedNumber / 100).toFixed(2));
};

/**
 * 将一个分数转换为整数
 * @param num
 */
export const convertToInteger = (num: number | string | undefined): number => {
	if (typeof num === 'undefined') return 0;
	const parsedNumber = typeof num === 'string' ? parseFloat(num) : num;
	// TODO 分转元后还有小数则四舍五入
	return Math.round(parsedNumber * 100);
};

/**
 * 将一个数转换为 1.00 这样
 * 数据呈现的时候使用
 *
 * @param num 整数
 */
export const floatToFixed2 = (num: number | string | undefined): string => {
	let str = '0.00';
	if (typeof num === 'undefined') {
		return str;
	}
	const f = formatToFraction(num);
	const decimalPart = f.toString().split('.')[1];
	const len = decimalPart ? decimalPart.length : 0;
	switch (len) {
		case 0:
			str = f.toString() + '.00';
			break;
		case 1:
			str = f.toString() + '0';
			break;
		case 2:
			str = f.toString();
			break;
	}
	return str;
};

/**
 * 元转分
 */
export const yuanToFen = (amount: string | number): number => {
	return Math.round(Number(amount) * 100);
};

/**
 * 分转元
 */
export const fenToYuan = (amount: string | number): number => {
	return Number((Number(amount) / 100).toFixed(2));
};

// 防抖: 只执行最后一次, 定时器内触发则重新计时
export const debounceDirective = {
	beforeMount(el, binding) {
		let timer;
		const { arg, value: { fn, time, keys, params } } = binding;
		el.addEventListener(arg || "input", () => {
			clearTimeout(timer);
			timer = setTimeout(() => {
				fn(keys, params);
			}, time || 600); // 600毫秒防抖延迟，可以根据需求调整
		});
	},
};

// 节流: 控制执行次数, 定时器结束才会再次触发
export const throttleDirective: Directive<HTMLElement, (...args: any[]) => void> = {
	mounted(el, binding) {
		let timeout:any = null;
		const handler = () => {
			if (timeout) return;
			binding.value();
			timeout = setTimeout(() => {
				timeout = null;
			}, 500); // 节流时间，可以作为参数传递
		};

		el.addEventListener('click', handler);
	},
	beforeUnmount(el) {
		el.removeEventListener('click', el._v_throttleHandler);
	}
};

// 日期转时间戳
export const getTimestamp = value => {
	return new Date(value).getTime() / 1000;
};

// 获取当前时间
export const getCurrentDate = () => {
	const date = new Date();
	const year = date.getFullYear() + '';
	const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1;
	const day = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate();
	const h = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours();
	const m = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes();
	const s = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds();
	return `${year}-${month}-${day} ${h}:${m}:${s}`;
};

// 判断某个字符出现过几次
export const getCountSymbol = (symbol, str) => {
	// 使用正则表达式，'g'标志表示全局匹配
	const regex = new RegExp(symbol, 'g');
	// match()方法返回所有匹配的数组，数组长度即为出现次数
	return (str.match(regex) || []).length;
};

// a标签下载文件
export const downFile = async (fileUrl: string, fileName: string) => {
	try {
		// 使用 fetch API 下载文件
		const response = await fetch(fileUrl);
		const blob = await response.blob();
		const url = URL.createObjectURL(blob);
		const link = document.createElement('a');
		link.href = url;
		// 文件名和后缀
		link.download = `${fileName}`;
		// 将 <a> 标签添加到页面中并模拟点击下载
		document.body.appendChild(link);
		link.click();
		// 下载完成后移除 <a> 标签和 URL 对象
		document.body.removeChild(link);
		URL.revokeObjectURL(url);
	} catch (error) {
		console.error('Error downloading the file:', error);
	}
};

// 千分位
export const formatNumber = (value) => {
	if (!value) return;
	// 将数字转换为带有两位小数的格式
	const formattedValue = Number(value).toFixed(2);
	// 使用正则表达式添加千分位分隔符
	return formattedValue.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

// 判断两个对象除了特定值以外，是否都一样
export const isSame = (obj1, obj2, field) => {
	// 获取两个对象的键
	const keys1 = Object.keys(obj1).filter((key) => key !== field);
	const keys2 = Object.keys(obj2).filter((key) => key !== field);

	// 比较键的数量
	if (keys1.length !== keys2.length) {
		return false;
	}

	// 比较键的值
	for (const key of keys1) {
		if (obj1[key] !== obj2[key]) {
			return false;
		}
	}

	return true;
};

export const getDateDiff = (targetDate) => {
	const now = Date.now(); // 当前时间的时间戳（毫秒）
	const diff = now - new Date(targetDate).getTime(); // 时间差（毫秒）

	// 转换为秒、分钟、小时、天数
	const seconds = Math.floor(diff / 1000);
	const minutes = Math.floor(diff / (1000 * 60));
	const hours = Math.floor(diff / (1000 * 60 * 60));
	const days = Math.floor(diff / (1000 * 60 * 60 * 24));
	const month = Math.floor(diff / (1000 * 60 * 60 * 24 * 30));
	const years = Math.floor(diff / (1000 * 60 * 60 * 24 * 30 * 12));

	if (seconds < 60) return `刚刚`;
	if (minutes < 60) return `${minutes}分钟前`;
	if (hours < 24) return `${hours}小时前`;
	if (month < 12) return `${month}个月前`;
	if (years < 12) return `${years}年前`;
	return `${days} 天前`;
};


/**
 * 将时间转换为 `几秒前`、`几分钟前`、`几小时前`、`几天前`
 * @param param 当前时间，new Date() 格式或者字符串时间格式
 * @param format 需要转换的时间格式字符串
 * @description param 10秒：  10 * 1000
 * @description param 1分：   60 * 1000
 * @description param 1小时： 60 * 60 * 1000
 * @description param 24小时：60 * 60 * 24 * 1000
 * @description param 3天：   60 * 60* 24 * 1000 * 3
 * @returns 返回拼接后的时间字符串
 */
export function formatChatTime(timestamp: string | Date, type: string): string {
	const now = new Date();
	const messageDate = new Date(timestamp);
	
	const currentYear = now.getFullYear();
	const messageYear = messageDate.getFullYear();
	const currentMonth = now.getMonth();
	const messageMonth = messageDate.getMonth();
	const currentDay = now.getDate();
	const messageDay = messageDate.getDate();
  
	if (messageYear === currentYear && messageMonth === currentMonth && messageDay === currentDay) {
	  return `${messageDate.getHours()}:${messageDate.getMinutes() < 10 ? `0${messageDate.getMinutes()}` : messageDate.getMinutes()}`;
	} else if (messageYear === currentYear && messageDay === currentDay - 1) {
	  return `昨天 ${messageDate.getHours()}:${messageDate.getMinutes() < 10 ? `0${messageDate.getMinutes()}` : messageDate.getMinutes()}`;
	} else if (messageYear === currentYear) {
	  return `${messageDate.getMonth() + 1}/${messageDate.getDate()}
	  ${ type ? ` ${messageDate.getHours() < 10 ? `0${messageDate.getHours()}` : messageDate.getHours() }:${messageDate.getMinutes() < 10 ? `0${messageDate.getMinutes()}` : messageDate.getMinutes()}` : '' }`;
	} else {
	  return `${messageDate.getFullYear()}/${messageDate.getMonth() + 1}/${messageDate.getDate()}`;
	}
}
  
// 截图-创建img
export const createElementImg = (e, vnode, w = 200, h = 0) => {
	const img = document.createElement("img");
	img.src = e;
	img.alt = "图片加载失败";
	img.width = w;
	if (h) {
		img.height = h;
	}
	vnode.appendChild(img);
};

// 创建并触发自定义事件
export const sendMessage = (data) => {
    var event = new CustomEvent('receiveMessage', { detail: data });
    window.dispatchEvent(event);
}